(function(){
	'use strict';
	/**
	 *  zhx-ring-buttons
	 *
	 *  Author : Vicco Wang
	 *  Date   : 2016-09-22
	 *
	 *  依赖：
	 *  [AngularJS]
	 *  [velocity]
	 *  [jQuery] 依赖$selector部分
	 *
	 *  说明：
	 *  该组件可以在任意地方调用，不过一般情况下作为按钮的右键菜单（只有1级）的替代品；
	 *  它的展现形式会以当前点击的坐标为圆心，所有按钮都会围绕该圆心形成一个圆，并配有缓动效果；
	 *
	 *  用法：
	 *  View:
	 *  <span zhx-ring-button="ringOptions">button</span>
	 *
	 *  controller:
	 *  $scope.ringOptions = {
	 *  	ringWraperRadius : 130,	//圆形整体的半径 默认值：100
	 *  	ringRadius : 50,		//圆形按钮的直径 默认值：45
	 *  	duration : 50,			//缓动效果持续时间，数字越大时间越久   默认值：35
	 *  	rings : [
	 *  		//按钮数据定义
	 *  		//@name  按钮的文字
	 *  		//@image 按钮的图标
	 *  		//@event 按钮的点击事件
	 *  		{ "name": "buttons", "image": "imageClass", "event": "someButtonEvent" }	
	 *  	]
	 *  };
	 *
	 *  //controller中可以继续定义按钮的点击事件
	 *  //在按钮的点击事件中可以接收到两个参数
	 *  @event 当前点击的事件
	 *  @scope 当前按钮的作用域
	 *  
	 *  $scope.someButtonEvent = function(event, scope ){
	 *  	//do sth after click button
	 *  }
	 * 
	 */
	var app = angular.module('zhx-ring-buttons', []);

	/**
	 * 用于生成按钮坐标的服务
	 */
	app.factory('zhxRingCreateService',function(){
		var service = {};

			/**
			 * 根据参数获得一个具有XY坐标的dot对象
			 * @param x0,y0 圆心坐标
			 * @param r 半径
			 * @param a 角度
			 **/
			 var __createRingWithXY = function(x0, y0, rR, r, a){
				var ring = {};
				ring.x = Math.floor( x0 - rR/2 + r * Math.sin(a * Math.PI / 180) );
				ring.y = Math.floor( y0 - rR/2 + r * Math.cos(a * Math.PI / 180) );
				ring.radius = rR;

				return ring;
			};

			/**
			 * 根据按钮数量生成一个包含按钮距离圆心角度的数组
			 * @param  {[type]} num [description]
			 * @return {[type]}     [description]
			 */
			var __createRingAngel = function(num){
				var angleArray = [];
				var deg = 360 / num;

				for (var i = 0; i < num; i++){
					angleArray.push(deg - 90 + deg * i );
				}

				return angleArray;
			};

			/**
			 * 创建并返回一组拥有XY坐标的ring对象
			 * 该坐标为ring最终在页面上的坐标位置
			 * 
			 * @param  {[type]} x   [圆心坐标X]
			 * @param  {[type]} y   [圆心坐标Y]
			 * @param {[type]}  rR  [ring半径]
			 * @param  {[type]} r   [圆半径]
			 * @param  {[type]} num [生成数量]
			 * @return { array } [一组拥有XY坐标的ring对象]
			 */
			service.createRing = function(ringData){

				if( !ringData.ringTotalNum ) return;

				var ringX = ringData.circleX,
					ringY = ringData.circleY,
					ringRadius = ringData.circleRadius,
					radius = ringData.radius,
					ringTotal = ringData.ringTotalNum,
					ringsArray = [],
					i = 0;

				var angels = __createRingAngel(ringTotal);
			
				for( ; i < ringTotal; i++ ){
					ringsArray.push( __createRingWithXY(ringX, ringY, ringRadius, radius, angels[i]) );
				}	

				return ringsArray;
			};

		return service;
	})


	app.directive("zhxRingButton",['$compile','$templateCache','$timeout','$q','zhxRingCreateService','$rootScope',function($compile,$templateCache,$timeout,$q,zhxRingCreateService,$rootScope){
		return {
			restrict : 'AE',
			scope : {
				zhxRingButton : '=',
				ringData :'='
			},
			link : function( scope, tElement, tAttrs ){
				//数据中不存在按钮时，不使用该组件
				if( !scope.zhxRingButton ) return;

				//为当前DOM绑定点击事件
				var __elementClickEvent = function( ev ){
					//页面同时只能显示唯一一个按钮群
					if( angular.element('.zhx-ring-btn-wrap').length ) return;

					var event = ev || window.event;

					event.stopPropagation();

					var eventTarget = event.target;
					//目标对象点击以后将目标置为半透明效果，来凸现接下来产生的按钮动效
					if( scope.zhxRingButton.styleClass ) angular.element(eventTarget).addClass( scope.zhxRingButton.styleClass );
					// angular.element(eventTarget).velocity({ 
					// 	opacity : .4
					// });
					var mask = angular.element('<div id="zhx-ring-button-mask"></div>');

					//为图标群添加一个父scope,以下每一个图标的scope都挂载在该scope下，以便移除时进行垃圾回收
					var ringWrapScope = scope.zhxRingButton.scope.$new() || scope.$new();
					//为组件初始一个坐标点，该坐标点将来会在点击事件触发后，获得点击时的坐标
					ringWrapScope.elementCoord = {
						x : 0,
						y : 0
					}

					//设定当前点击位置相对页面的坐标 
					ringWrapScope.elementCoord.x = event.pageX;
					ringWrapScope.elementCoord.y = event.pageY;

					/**
					 * 创建即将要生成的小图标的配置项
					 * @type {Object}
					 * circleX 圆心X坐标
					 * circleY 圆心Y坐标
					 * radius  圆半径
					 * ringTotalNum  图标数量
					 */
					ringWrapScope.createRingData = {
						circleX : ringWrapScope.elementCoord.x,
						circleY : ringWrapScope.elementCoord.y,
						circleRadius : scope.zhxRingButton.ringRadius || 45,
						radius  : scope.zhxRingButton.ringWraperRadius || 100,
						ringTotalNum  : scope.zhxRingButton.rings.length
					};

					/**
					 * 生成数组为圆心周围指定数量的图标坐标位置
					 * @return { Array } [数组对象中包含XY坐标]
					 */
					var ringsArray = zhxRingCreateService.createRing(ringWrapScope.createRingData);
					//设置一个动画间隔时间，按钮要一个一个出现
					var interval = scope.zhxRingButton.duration || 35;

					var ringWrap = $compile('<div class="zhx-ring-btn-wrap"></div>')(ringWrapScope);
						ringWrap.css({
							left : event.pageX,
							top : event.pageY
						});

					mask.appendTo('body');

					ringWrap.appendTo('body');

					angular.element('html,body').addClass('hidden-body');

					/**
					 * 按照传入的按钮个数来生成DOM按钮，DOM按钮绑定事件
					 */
					angular.forEach(ringsArray, function(ring,key){
						/**
						 * 每一个按钮都会有自有属性以及方法，因此这里需要为每一个按钮创建新的作用域[scope]
						 * @scope {object}
						 */
						var ringScope = ringWrapScope.$new();
						//初始创建图标的配置项，传递给每一个小按钮做属性
						ringScope.name =  scope.zhxRingButton.rings[key].name;
						//按钮缓动效果需要一个起始坐标，该坐标目前设置为当前鼠标点击的坐标，即圆心坐标
						ringScope.coord = {
							x : event.pageX - ring.radius / 2,
							y : event.pageY - ring.radius / 2
						};
						//该对象放一些按钮的样式属性
						ringScope.style = {
							radius : ring.radius,
							color : scope.zhxRingButton.rings[key].color,
							icon  : scope.zhxRingButton.rings[key].icon
						};

						//创建图标模板
						var ringsTpl = $compile( $templateCache.get('zhxRingButtonTpl.vicco') )(ringScope);

						//设置一个图标动画延迟promise
						//保证动画完成后再绑定相应事件，防止动画进行中触发事件
						var ringsAnimatePromise = $q.defer();
						/**
						 * 单个按钮事件
						 * click / mouseover / mouseout
						 */
						 ringsAnimatePromise.promise.then(function(res){

						 	//one-click event
							ringScope._ringButtonClickEvent = function(event){
								//防止事件冒泡至顶层
								event.stopPropagation();
								//执行传递的当前按钮的事件，并返回参数event / clickTargetScope / scope
								try{
									ringWrapScope.$parent[ scope.zhxRingButton.rings[key].event  ].call( this, event, scope.ringData, ringScope );
								}catch(e){
									console.warn('未找到该按钮定义的事件');
								}

							};

							var isMouseover = false;
							var overTime;
							//mouse over event
							ringScope._ringButtonOverEvent = function(event){

								if( !overTime || overTime === 'finished' ){

									var ev = event || window.event,
										target = angular.element(event.target);
										overTime = 'unfinished';

										target.velocity({
											scale : 1.3
										},{
											easing : 'spring',
											duration : 350,
											complete : function(){
												overTime = 'finished';
											}
										});
										isMouseover = true;
								}
								
							};
							//mouse out event
							ringScope._ringButtonOutEvent = function(event){
								// console.log('out');
								var ev = event || window.event,
									target = angular.element(event.target);

									if( isMouseover ) {
										target.velocity('reverse');
										isMouseover = !isMouseover;
									}
							};

						 });
							
						//添加至DOM树
						ringsTpl.appendTo(ringWrap);

						/**
						 * 使用velocity创建延迟动画
						 * 注：这里不更新scope作用域中的coord坐标，使用动画组件来实现缓动效果
						 */
						$timeout(function(){

							ringsTpl.velocity({
								left : ring.x,
								top : ring.y,
								opacity : .97
							},{
								delay : 20 + key * interval * 1.1 ,
								easing : 'spring',
								duration : 800,
								complete : function($element){
									ringsAnimatePromise.resolve($element);	
								}
							});

						},50);

					});

					/**
					 * 因为是手动创建的点击事件，因此这里需要手动更新作用域
					 */
					scope.$digest();

					/**
					 * 移除按钮群事件
					 */
					var __removeRingBtn = function( ev ){

						var event = ev || window.event;
						event.stopPropagation();

						//移除按钮
						ringWrap.velocity({
							opacity : 0
						},{
							duration : 100,
							complete : function(){
								//动画后移除作用域，DOM以及注销事件
								$timeout(function(){
									ringWrapScope.$destroy();
									ringWrap.remove();	
									angular.element('html,body').off("click", __removeRingBtn);
									angular.element('html,body').removeClass('hidden-body');
									mask.remove();
									//重置事件对象
									// angular.element(eventTarget).velocity('reverse');
									if( scope.zhxRingButton.styleClass ) angular.element(eventTarget).removeClass( scope.zhxRingButton.styleClass );
									//最后广播一个rings button 关闭的通知
									$rootScope.$broadcast( 'zhx.ringsbutton.closed', { ringScope : ringWrapScope, targetData : scope.ringData } );	
								},100)
							}
						});
					};
					//每次最后给全局绑定一个移除按钮事件，该事件在触发后注销
					angular.element('html,body').on("click", __removeRingBtn);
					//广播一个自定义通知
					$rootScope.$broadcast( scope.zhxRingButton.broadcastEvent, ringWrapScope );
					//广播一个rings button 打开的通知
					$rootScope.$broadcast( 'zhx.ringsbutton.opened', { ringScope : ringWrapScope, targetData : scope.ringData } );	
				};

				//暂时绑定一个事件
				tElement.on("click",__elementClickEvent);

			}

		}

	}])
	//单个按钮模板
	app.run(function($templateCache){
		$templateCache.put('zhxRingButtonTpl.vicco',
			'<div class="zhx-ring-btn {{ style.icon }} {{ style.color }}" ' +
				'ng-style="{ width: style.radius, height: style.radius, top: coord.y, left: coord.x }" ' +
				'ng-click="_ringButtonClickEvent($event)" ' +
				'ng-mouseover="_ringButtonOverEvent($event)" ' +
				'ng-mouseout="_ringButtonOutEvent($event)" ' +
				'>' +
					// '{{ ::name }}' +
				'</div>'
		);
	})
	

})()